/*
 *  Copyright (c) 2008 Howard Shank
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to use, 
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
 * Software, and to permit persons to whom the Software is furnished to do so, subject 
 * to the following conditions:

 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
// README
//
//
/// TODO: overcome MSIE behavior for initial selection of listItem
/// TODO: prevent selected listItem from changing once dragging begins
/// TODO: fix action type to move/copy instead of true/false
/// TODO: Enhance functionality to operate on listbox with multiple property set to true
//          currently extension will only function on single listItem selection.
//          Multiple selection results are unpredictable, although this s not specifically prevented.
/// TODO: Enhance functionality to operate bi-directionally.
//          currently allowing bi-directional functionality LB1->LB2 LB1<-LB2 has
//          unpredictable results, although this is not specifically prevented.
/// TODO: Sorting of insertions? Best left control? What about multiples when coded?
/// TODO: Enhance functionality to use transparency for dragging
/// TODO: optimize
/// TODO: submit to AJAX for inclusion in AJAX Control Tool Kit

Type.registerNamespace('AjaxCtrlsExtenders');

AjaxCtrlsExtenders.DragMode = function() {
    /// <summary>
    /// The DragMode enumeration is used to specify the action is either move or copy.
    /// </summary>
    throw Error.invalidOperation();
}
// SYNC with class if changes
AjaxCtrlsExtenders.DragMode.prototype = {
    Move : 1,
    Copy : 2
}
AjaxCtrlsExtenders.DragMode.registerEnum("AjaxCtrlsExtenders.DragMode", false);


AjaxCtrlsExtenders.DragDropListboxBehavior = function(element) {
    /// <summary>
    /// This extender can be attached to a pair of listboxes to enable drag and drop functionality
    /// between the boxes. Only one way functionality is supported at this time.
    /// </summary>

    AjaxCtrlsExtenders.DragDropListboxBehavior.initializeBase(this, [element]);

    // property variables here
    //
    
    // AJAX properties - from Class
    this._DropTargetID = null;
    this._Action = AjaxCtrlsExtenders.DragMode.Move;
    this._Unique = true;
    
    // this objects used in javascript
    this.eventTargetElement = null;
    this.thisElement = null;
    this.dropTargetElement = null;
    
    // this object properties for drag and drop
    this.offsetMouseDiv = 0;    // any positive value moves mouse inside the div and causes problems
    this.isDragging = null;
    this.selectedIndex = null;
    this.selectedValue = null;
    this.selectedText = null;
    
    // delegates to setup and teardown events
    // tried without delegates, but can't seem to get the wiring to function properly
    this._onafterupdateDelegate = null;
    this._onclickDelegate = null;
    this._ondblclickDelegate = null;
    this._onmousemoveDelegate = null;
    this._onmouseoverDelegate = null;
    this._onmouseoutDelegate = null;
    this._onchangeDelegate = null;
    this._onmousedownDelegate = null;
    this._onmouseupDelegate = null;
    this._onmousemoveBodyDelegate = null;
    
    this.xoffset = 2;
    this.yoffset = -5;
    
    // SELECT CONTROL availalable events
//    onactivate
//    onbeforeactivate
//    onbeforecopy
//    onbeforecut
//    onbeforedeactivate
//    onbeforedeactivate
//    onbeforeeditfocus
//    onbeforepaste
//    onblur
//    onchange
//    onclick
//    oncontextmenu
//    oncontrolselect
//    oncopy
//    oncut
//    ondatabinding
//    ondblclick
//    ondeactivate
//    ondisposed
//    ondrag
//    ondragend
//    ondragenter
//    ondragleave
//    ondragover
//    ondragstart
//    ondrop
//    onfocus
//    onfocusin
//    onfocusout
//    onhelp
//    oninit
//    onkeydown
//    onkeypress
//    onkeyup
//    onload
//    onlosecapture
//    onmousedown
//    onmouseenter
//    onmouseleave
//    onmousemove
//    onmouseout
//    onmouseover
//    onmouseup
//    onmousewheel
//    onmose
//    onmoveend
//    onmovestart
//    onpaste
//    onprerender
//    onpropertychange
//    onreadystatechange
//    onresize
//    onresizeend
//    onresizestart
//    onselectstart
//    onserverchange
//    onunload
    
    //BROWSER INFO //
    //==================begin browser properties================
    this.is_major = null;
    this.is_minor = null;

    // Note: Opera and WebTV spoof Navigator.  We do strict client detection.
    // If you want to allow spoofing, take out the tests for opera and webtv.
    this.is_nav  = null;
    this.is_nav2 = null;
    this.is_nav3 = null;
    this.is_nav4 = null;
    this.is_nav4up = null;
    this.is_navonly = null;
    this.is_nav6 = null;
    this.is_nav6up = null;
    this.is_gecko = null;


    this.is_ie     = null;
    this.is_ie3    = null;
    this.is_ie4    = null;
    this.is_ie4up  = null;
    this.is_ie5    = null;
    this.is_ie5_5  = null;
    this.is_ie5up  = null;
    this.is_ie5_5up =null;
    this.is_ie6    = null;
    this.is_ie6up  = null;
    this.is_ie7    = null;
    this.is_ie7up  = null;

    // KNOWN BUG: On AOL4, returns false if IE3 is embedded browser
    // or if this is the first browser window opened.  Thus the
    // variables is_aol, is_aol3, and is_aol4 aren't 100% reliable.
    this.is_aol   = null;
    this.is_aol3  = null;
    this.is_aol4  = null;
    this.is_aol5  = null;
    this.is_aol6  = null;

    this.is_opera = null;
    this.is_opera2 = null;
    this.is_opera3 = null;
    this.is_opera4 = null;
    this.is_opera5 = null;
    this.is_opera5up = null;

    this.is_webtv = null;

    this.is_TVNavigator = null;
    this.is_AOLTV = null;

    this.is_hotjava = null;
    this.is_hotjava3 = null;
    this.is_hotjava3up = null;

    this.is_js = null;

    // *** PLATFORM ***
    this.is_win   = null;
    // NOTE: On Opera 3.0, the userAgent string includes "Windows 95/NT4" on all
    //        Win32, so you can't distinguish between Win95 and WinNT.
    this.is_win95 = null;

    // is this a 16 bit compiled version?
    this.is_win16 = null;

    this.is_win31 = null;

    this.is_winme = null;
    this.is_win2k = null;
    this.is_win2k3 = null;
    this.is_winXP = null;
    this.is_winVista = null;
    this.is_win2k8 = null;

    // NOTE: Reliable detection of Win98 may not be possible. It appears that:
    //       - On Nav 4.x and before you'll get plain "Windows" in userAgent.
    //       - On Mercury client, the 32-bit version will return "Win98", but
    //         the 16-bit version running on Win98 will still return "Win95".
    this.is_win98 = null;
    this.is_winnt = null;
    this.is_win32 = null;
    this.is_win64 = null;

    this.is_os2   = null;

    this.is_mac    = null;
    this.is_safari = null;
    // hack ie5 js version for mac
    this.is_mac68k = null;
    this.is_macppc = null;

    this.is_sun   = null;
    this.is_sun4  = null;
    this.is_sun5  = null;
    this.is_suni86= null;
    this.is_irix  = null;
    this.is_irix5 = null;
    this.is_irix6 = null;
    this.is_hpux  = null;
    this.is_hpux9 = null;
    this.is_hpux10= null;
    this.is_aix   = null;
    this.is_aix1  = null;
    this.is_aix2  = null;
    this.is_aix3  = null;
    this.is_aix4  = null;
    this.is_linux = null;
    this.is_sco   = null;
    this.is_unixware = null;
    this.is_mpras    = null;
    this.is_reliant  = null;
    this.is_dec   = null;
    this.is_sinix = null;
    this.is_freebsd = null;
    this.is_bsd = null;
    this.is_unix  = null;
    this.is_vms   = null;
    //==================End browser properties================
    

}

AjaxCtrlsExtenders.DragDropListboxBehavior.prototype = {
    initialize : function() {
        AjaxCtrlsExtenders.DragDropListboxBehavior.callBaseMethod(this, 'initialize');
        //Sys.Debug.trace("***************initialize " + this.get_element().id);
        
        this._DetectBrowserInfo();
        
        ////Sys.Debug.trace("DragDropListbox
        // TODO: add your initalization code here
        //this._Unique = true;
        this._resetDragging();
        
        var element = this.get_element();
        var elementTarget = $get(this._DropTargetID);
        element.selectedIndex = -1; // force no selection
        // Add handlers to this control
        // onmouseover
        // onmouseout
        // onchange
        // onmousedown
        // onmouseup
        // Add handlers to the dropTargetID control
        // onmouseover
        // onmouseout
        // onmouseup
        if(this._onclickDelegate == null)
        {
            this._onclickDelegate = Function.createDelegate(this, this._onclickHandler);
        }
        $addHandler(element, 'click', this._onclickDelegate);

        if(this._ondblclickDelegate == null)
        {
            this._ondblclickDelegate = Function.createDelegate(this, this._ondblclickHandler);
        }
        $addHandler(element, 'dblclick', this._ondblclickDelegate);
        
        if(this._onafterupdateDelegate == null)
        {
            this._onafterupdateDelegate = Function.createDelegate(this, this._onafterupdateHandler);
        }
        $addHandler(element, 'afterupdate', this._onafterupdateDelegate);
        
        if(this._onmousemoveDelegate == null)
        {
            this._onmousemoveDelegate = Function.createDelegate(this, this._onmousemoveHandler);
        }
        $addHandler(element, 'mousemove', this._onmousemoveDelegate);
        
        if(this._onmouseoverDelegate == null)
        {
            this._onmouseoverDelegate = Function.createDelegate(this, this._onmouseoverHandler);
        }
        $addHandler(element, 'mouseover', this._onmouseoverDelegate);
        $addHandler(elementTarget, 'mouseover', this._onmouseoverDelegate);

        if(this._onmouseoutDelegate == null)
        {
            this._onmouseoutDelegate = Function.createDelegate(this, this._onmouseoutHandler);
        }
        $addHandler(element, 'mouseout', this._onmouseoutDelegate);
        $addHandler(elementTarget, 'mouseout', this._onmouseoutDelegate);
        
        if(this._onchangeDelegate == null)
        {
            this._onchangeDelegate = Function.createDelegate(this, this._onselectionChangedHandler);
        }
        $addHandler(element, 'change', this._onchangeDelegate);
        
        if(this._onmousedownDelegate == null)
        {
            this._onmousedownDelegate = Function.createDelegate(this, this._onmousedownHandler);
        }
        $addHandler(element, 'mousedown', this._onmousedownDelegate);
        
        if(this._onmouseupDelegate == null)
        {
            this._onmouseupDelegate = Function.createDelegate(this, this._onmouseupHandler);
        }
        $addHandler(element, 'mouseup', this._onmouseupDelegate);
        $addHandler(elementTarget, 'mouseup', this._onmouseupDelegate);

        if(this._onmousemoveBodyDelegate == null)
        {
            this._onmousemoveBodyDelegate = Function.createDelegate(this, this._onmousemoveBodyHandler);
        }
        $addHandler($get("form1"), 'mousemove', this._onmousemoveBodyDelegate);
    },

    dispose : function() {
        // TODO: add your cleanup code here
        var element = this.get_element();
        var elementTarget = $get(this._DropTargetID);
        
        if(this._onmousemoveBodyDelegate)
        {
            $removeHandler($get("form1"), 'mousemove', this._onmousemoveBodyDelegate);
            delete this._onmousemoveBodyDelegate;
        }

        if(this._onclickDelegate)
        {
            $removeHandler(element, 'click', this._onclickDelegate);
            delete this._onclickDelegate;
        }
        
        if(this._ondblclickDelegate)
        {
            $removeHandler(element, 'dblclick', this._ondblclickDelegate);
            delete this._ondblclickDelegate;
        }
        
        if(this._onafterupdateDelegate)
        {
            $removeHandler(element, 'afterupdate', this._onafterupdateDelegate);
            delete this._onafterupdateDelegate;
        }
        
        if(this._onmousemoveDelegate)
        {
            $removeHandler(element, 'mousemove', this._onmousemoveDelegate);
            delete this._onmousemoveDelegate;
        }
        
        if(this._onmouseoverDelegate)
        {
            $removeHandler(element, 'mouseover', this._onmouseoverDelegate);
            $removeHandler(elementTarget, 'mouseover', this._onmouseoverDelegate);
            delete this._onmouseoverDelegate;
        }
        
        if(this._onmouseoutDelegate)
        {
            $removeHandler(element, 'mouseout', this._onmouseoutDelegate);
            $removeHandler(elementTarget, 'mouseout', this._onmouseoutDelegate);
            delete this._onmouseoutDelegate;
        }
        
        if(this._onchangeDelegate)
        {
            $removeHandler(element, 'change', this._onchangeDelegate);
            delete this._onchangeDelegate;
        }
        
        if(this._onmousedownDelegate)
        {
            $removeHandler(element, 'mousedown', this._onmousedownDelegate);
            delete this._onmousedownDelegate;
        }
        
        if(this._onmouseupDelegate)
        {
            $removeHandler(element, 'mouseup', this._onmouseupDelegate);
            $removeHandler(elementTarget, 'mouseup', this._onmouseupDelegate);
            delete this._onmouseupDelegate;
        }
        
        AjaxCtrlsExtenders.DragDropListboxBehavior.callBaseMethod(this, 'dispose');
    },

    // property accessors here
    //
    get_DropTargetID : function() {
        return this._DropTargetID;
    },

    set_DropTargetID : function(value) {
        this._DropTargetID = value;
    },
    
    get_Action : function() {
        return this._Action;
    },

    set_Action : function(value) {
        this._Action = value;
    },

    get_Unique : function() {
        return this._Unique;
    },

    set_Unique : function(value) {
        this._Unique = value;
    },

    // utility and functionality begins here
    _fixupEvent : function(e) {
        
        if(this.is_nav4up){
        }
        if(this.is_ie5up){
            e=window.event;
        }
        //Sys.Debug.assert(e!=null, "e is null", true);
        //Sys.Debug.assert(e!="undefined", "e is undefined", true);
        return e;
    },
        
    _getEventTarget : function(e) {
        var targ = null;
	    if (e.target)
	    {
	        targ = e.target;
	    }
	    else 
	    {
	        if (e.srcElement)
	        {
	            targ = e.srcElement;
	        }
	    }
	    if (targ)
	    {
	        if (this.is_safari && targ.nodeType == 3) // defeat Safari bug
	        {
        		targ = targ.parentNode;
            }
        }
        
        //Sys.Debug.assert(targ!=null, "targ is null", true);
        //Sys.Debug.assert(targ!="undefined", "targ is undefined", true);

        return targ;
    },
    
    _validateElement : function(elem) {
        //Sys.Debug.assert(elem!=null, "elem is null", true);
        //Sys.Debug.assert(elem!="undefined", "elem is undefined", true);
        if(elem == null || elem == "undefined") return false;
        return true;
    },
    GetHiddenField : function(name) {
        return $get(name);
    },
    
    _AddListItem : function(listName, text, value) {
      var hiddenField = this.GetHiddenField(listName.id + 'DataAdd');
     
      if (hiddenField != null)
      {
        // Add a separator
        var tmp = hiddenField.value;
        if (tmp != '')
          hiddenField.value += ',';
     
        // Add the item to the hidden field
        hiddenField.value += text + '|' + value;
     
        // if present in the REMOVED hidden field, remove it
        var removeHiddenField = this.GetHiddenField(listName.id + 'DataRemove');
        if (removeHiddenField != null)
        {
          var removedItems = removeHiddenField.value.split(',');
          removeHiddenField.value = '';
          var removed = false;
          for (var i = 0; i < removedItems.length; i++)
          {
            if (value != removedItems[i] && !removed)
            {
              // Add a separator
              var tmp1 = removeHiddenField.value;
              if (tmp1 != '')
                removeHiddenField.value += ',';
     
              removeHiddenField.value += removedItems[i];
            }
            else{
                removed = true;
            }
          }
        }
      }
    },
    
    _RemoveListItem : function(listName, value) {
        var hiddenField = this.GetHiddenField(listName.id + 'DataRemove');
 
        if (hiddenField != null) {
            // Add a separator
            var tmp = hiddenField.value;
            if (tmp != '') {
                hiddenField.value += ',';
            }
 
            hiddenField.value += value;
 
            // if present in the ADDED hidden field, remove it
            var addHiddenField = this.GetHiddenField(listName.id + 'DataAdd');
            if (addHiddenField != null) {
                var addedItems = addHiddenField.value.split(',');
                addHiddenField.value = '';
                var removed = false;
                for (var i = 0; i < addedItems.length; i++) {
                    if (addedItems[i].match(value) == null && !removed) {
                        // Add a separator
                        var tmp1 = addHiddenField.value;
                        if (tmp1 != '') {
                            addHiddenField.value += ',';
                        } // end if
             
                        addHiddenField.value += addedItems[i];
                    }
                    else {
                        removed = true;
                    }
                }   // end for
            }   // end if
        } //end if
    },
    
    _onclickHandler : function(e) {
//        debugger;
        //alert("_onclickHandler entered");
//        Sys.Debug.trace("_onclickHandler"); 
//        this.debug("_onclickHandler");
        
        e = this._fixupEvent(e);
        var thisElement = this.get_element();
    },

    _ondblclickHandler : function(e) {
//        Sys.Debug.trace("_ondblclickHandler"); 
//        this.debug("_ondblclickHandler");

        e = this._fixupEvent(e);
        var thisElement = this.get_element();
        if(thisElement.selectedIndex == -1)
        {
            return;
        }
        
        this._doMoveOrCopy(thisElement, $get(this._DropTargetID));
    },

    debug : function(str) {
        var out = document.getElementById('debugoutputdiv');
        out.innerHTML += "<br />" + str;
    },
    
     _onmousedownHandler : function (e){
        //debugger;
//        this.debug("_onmousedownHandler");
//        Sys.Debug.trace("_onmousedownHandler");
        
        // nothing selected yet, do not handle this event yet.
        e = this._fixupEvent(e);

        var eventTargetElement = this._getEventTarget(e);
        var thisElement = this.get_element();
        
        var dropTargetElement = $get(this._DropTargetID);
        if(thisElement.selectedIndex == -1)
        {
            return;
        }


        if(!this._validateElement(eventTargetElement)) {
            //Sys.Debug.trace("ERROR: _ondblclickHandler:: eventTargetElement is null or undefined");
            return;
        }

        if(!this._validateElement(thisElement)) {
            //Sys.Debug.trace("ERROR: _ondblclickHandler:: thisElement is null or undefined");
            return;
        }

        if(!this._validateElement(dropTargetElement)) {
            //Sys.Debug.trace("ERROR: _ondblclickHandler:: dropTargetElement is null or undefined");
            return;
        }
        
        //Sys.Debug.trace("thisElement=[" + thisElement.id + "]");
        //Sys.Debug.trace("1. thisElement.selectedIndex=[" + thisElement.selectedIndex + "]");

        // HACK to set selected item current - Still doesn't work. need to overcome this
        // MSIE problem.
//        if(!this.isDragging)
//        {
//            thisElement.blur();
//            dropTargetElement.focus();
//            thisElement.focus();
//        }
        this.isDragging = true;
        this.selectedIndex = thisElement.selectedIndex;
        this._create_div_dynamic(e);
        //dropTargetElement.focus();
        
        //DEBUGGING HERE DOWN TO END OF FUNCTION
//        //Sys.Debug.trace("2. thisElement.selectedIndex=[" + thisElement.selectedIndex + "]");
//        var mouseX = e.x;
//        var mouseY = e.y;
//        var eStyle = thisElement.style;
//        var posTop = eStyle.posTop;
//        var size = thisElement.size;
//        var sourceElement = thisElement.sourceIndex;
//        var children = thisElement.childNodes;
//        //Sys.Debug.trace("mouseY[" +mouseY+ "]");
//        //Sys.Debug.trace("offsetY[" +e.offsetY+ "]");
//        //Sys.Debug.trace("posTop[" + posTop+ "]size[" +size+ "]");
//        //Sys.Debug.trace("clientTop[" + thisElement.clientTop + "]");
//        //Sys.Debug.trace("clientHeight[" + thisElement.clientHeight + "]");
//        //Sys.Debug.trace("style.height[" + thisElement.style.height + "]");
//        //Sys.Debug.trace("style.lineHeight[" + thisElement.style.lineHeight + "]");
//        //Sys.Debug.trace("pixelHeight[" + thisElement.style.pixelHeight + "]");
//        //Sys.Debug.trace("padding[" + thisElement.style.padding + "]");
//        //Sys.Debug.trace("offsetX[" + thisElement.offsetX+ "]");
//        //Sys.Debug.trace("scrollTop[" + thisElement.scrollTop+ "]");
//        //Sys.Debug.trace("scrollHeight[" + thisElement.scrollHeight+ "]");
//        var scrollTop = thisElement.scrollTop;
//        //Sys.Debug.trace(".scrollHeight[" + scrollTop+ "]");
//        //Sys.Debug.trace("Top Item according to scroll bar [" + Math.round(scrollTop/(thisElement.scrollHeight/size))+ "]");
//        //Sys.Debug.trace("Item selected=[" + Math.round(e.offsetY/(thisElement.clientHeight/size))+ "]");
//        ////Sys.Debug.fail("break: ");    
//        //DEBUGGING HERE UP
    },    
    
    _onmouseoutHandler : function(e) {
        //Sys.Debug.trace("_onmouseoutHandler");
        //this.debug("_onmouseoutHandler");

        e = this._fixupEvent(e);
        var eventTargetElement = this._getEventTarget(e);
        var thisElement = this.get_element();
        var dropTargetElement = $get(this._DropTargetID);

        //Sys.Debug.trace("e=[" + e + "]");
    
        if(eventTargetElement == null) {
            //Sys.Debug.trace("ERROR: eventTargetElement is null");
            return;
        }
        if(thisElement == null) {
            //Sys.Debug.trace("ERROR: thisElement is null");
            return;
        }
        
        //Sys.Debug.trace("eventTargetElement=[" + eventTargetElement.id + "] thisElement=[" + thisElement.id + "]");
    },
    
    _onmousemoveBodyHandler : function(e) {
        //Sys.Debug.trace("_onmousemoveBodyHandler");
        if(!this.isDragging) return;
        this._onmousemoveHandler(e);
    },
    
    _onmousemoveHandler : function(e) {
        //Sys.Debug.trace("_onmousemoveHandler");
        if (!this.isDragging) return;
        e = this._fixupEvent(e);
        var mousePos = this._mouseCoords(e);
        var eventTargetElement = this._getEventTarget(e);
        var thisElement = this.get_element();
        var dropTargetElement = $get(this._DropTargetID);

        var lineHeight = Math.ceil(thisElement.clientHeight/thisElement.size);

        var dv = document.getElementById('dnd_dynamic_div'); // get dynamically div tag
        if(dv)
        {
            dv.style.left=(mousePos.x+this.xoffset) + "px";
            dv.style.top=(mousePos.y+this.yoffset - lineHeight) + "px";
        }
        var ifr = document.getElementById('dnd_dynamic_ifr'); // get dynamically iframe tag
        if(ifr)
        {
            ifr.style.left=(mousePos.x+this.xoffset) + "px";
            ifr.style.top=(mousePos.y+this.yoffset - lineHeight) + "px";
        }
//        // debug info
//        var scrollLeft = (document.body.scrollLeft==null) ? -1 : document.body.scrollLeft;
//	    var clientLeft = (document.body.clientLeft==null) ? -1 : document.body.clientLeft;
//	    var scrollTop = (document.body.scrollTop==null) ? -1 : document.body.scrollTop;
//	    var clientTop = (document.body.clientTop==null) ? -1 : document.body.clientTop;

//        window.status = "SI=" + thisElement.selectedIndex + " Mouse X=" +  e.x + " Y=" + e.y + 
//            " Target Left=" + dropTargetElement.offsetLeft+ 
//            " Right=" + (dropTargetElement.offsetLeft+dropTargetElement.clientWidth)+
//            " Top=" +dropTargetElement.offsetTop + 
//            " Bottom =" + (dropTargetElement.offsetTop+dropTargetElement.clientHeight) +
//            " " + scrollLeft + ":" + clientLeft + ":" + scrollTop + ":" +clientTop +
//            ":" + ((e.clientX==null) ? -1 : e.clientX) + ":" + ((e.clientY==null) ? -1 : e.clientY)
//            ;
    },
   
    
    _onafterupdateHandler : function(e)
    {
        //Sys.Debug.trace("_onafterupdateHandler");
        //this.debug("_onafterupdateHandler");

        e = this._fixupEvent(e);
        var eventTargetElement = this._getEventTarget(e);
        var thisElement = this.get_element();
        var dropTargetElement = $get(this._DropTargetID);
        //Sys.Debug.trace("e=[" + e + "]");
       // //Sys.Debug.fail("break: _onafterupdateHandler");
    },
    
    _onselectionChangedHandler : function(e)
    {
//        Sys.Debug.trace("_onselectionChangedHandler");
//        this.debug("_onselectionChangedHandler");

        if(this.is_msie && !this.is_ie7)
        {
            if(!this.isDragging)
            {
                var ev = e;
                _onmousedownHandler(ev);
            }
        }    

        e = this._fixupEvent(e);
        var eventTargetElement = this._getEventTarget(e);
        var thisElement = this.get_element();
        var dropTargetElement = $get(this._DropTargetID);
        //Sys.Debug.trace("e=[" + e + "]");
        ////Sys.Debug.fail("break: _onselectionChangedHandler");

        ////Sys.Debug.trace("targ=[" + targ.id + "] element=[" + element.id + "]");

    },

    _onmouseoverHandler : function (e) {
//        Sys.Debug.trace("_onmouseoverHandler");
//        this.debug("_onmouseoverHandler");

        e = this._fixupEvent(e);
        var eventTargetElement = this._getEventTarget(e);
        ////Sys.Debug.trace("e=[" + e + "]");
        ////Sys.Debug.fail("break: _onmouseoverHandler");

        if(eventTargetElement == null) return;
        var thisElement = this.get_element();
        var dropTargetElement = $get(this._DropTargetID);
        //Sys.Debug.trace("eventTargetElement=[" + eventTargetElement.id + "] element=[" + thisElement.id + "]");
        
        var validDropTarget = false;
        if(eventTargetElement.id == thisElement.id  || eventTargetElement.id == dropTargetElement.id)
        {
            //Sys.Debug.trace("validDropTarget = true");
            validDropTarget = true;
            // brighten the div
        }
        else
        {
            //Sys.Debug.trace("validDropTarget = false");
            validDropTarget = false;
            // darken the div
        }
//        if(validDropTarget)
//        {
//            //eventTargetElement.focus();
//        }
    },

    _onmouseupHandler : function (e) {
//        Sys.Debug.trace("_onmouseupHandler");
//        this.debug("_onmouseupHandler");

        if(!this.isDragging) return;
        
        e = this._fixupEvent(e);
        var eventTargetElement = this._getEventTarget(e);
        var thisElement = this.get_element();
        var dropTargetElement = $get(this._DropTargetID);
        var validDropTarget = false;
        var mousePos = this._mouseCoords(e);
        //debugger;
        ////Sys.Debug.fail("break: _onmouseupHandler");
        //Sys.Debug.trace("eventTargetElement [" + eventTargetElement.id + "] targetElement [" + dropTargetElement.id + "]");
        //Sys.Debug.trace("mouseX["+e.x+"] mouseY["+e.y+"]");
        //Sys.Debug.trace("clientTop["+dropTargetElement.clientTop+"] bottom["+dropTargetElement.clientTop+dropTargetElement.clientHeight+"]");
        //Sys.Debug.trace("clientLeft["+dropTargetElement.clientLeft+"] right["+dropTargetElement.clientLeft+dropTargetElement.clientWidth+"]");
        if(mousePos.y>dropTargetElement.offsetTop && mousePos.y<dropTargetElement.offsetTop+dropTargetElement.clientHeight)//+dropTargetElement.scrollWidth)
        {
            if(mousePos.x>dropTargetElement.offsetLeft && mousePos.x<dropTargetElement.offsetLeft+dropTargetElement.clientWidth)//+dropTargetElement.scrollWidth)
            {
                validDropTarget = true;
            }
        }

        if(validDropTarget) 
        {
            this._doMoveOrCopy(thisElement, dropTargetElement);
        }
        else
        {
            //alert("drag/drop cancelled");
            //Sys.Debug.trace("drag/drop cancelled");
        }
        this.isDragging = false;
        this._delete_div_dynamic();
        if(dropTargetElement) {
            dropTargetElement.focus(); 
        }
        else {
            thisElement.focus(); 
        }
    },

    _doMoveOrCopy : function (sourceElement, targetElement) {
//            Sys.Debug.trace("_doMoveOrCopy entered");
//        this.debug("_doMoveOrCopy");

                // if valid target, perform copy/move action
            var valid = true;
            if(this.selectedText == "") return;
            if(this._Unique == true)
            {
                //Sys.Debug.trace("this._Unique == true");
                //Sys.Debug.trace("count=[" + targetElement.options.length + "]");
                // check if value is unique
                for(x=0;x<targetElement.options.length;x++)
                {
                    //Sys.Debug.trace("Checking item [" + x + "] value=[" + targetElement.options[x].innerHTML + "]"); 
                    if(targetElement.options[x].innerHTML == this.selectedText)
                    {
                        //Sys.Debug.trace("Duplicate found. Required to be unique.");
                        valid = false;
                        break;
                    }
                }
            }
            else
            {
                //Sys.Debug.trace("this._Unique == false");
            }
            if(valid)
            {
                // TODO: modify to use add method
                targetElement.options[targetElement.options.length] = new Option( this.selectedText, this.selectedValue);
                this._AddListItem(targetElement, this.selectedText, this.selectedValue);
                //Sys.Debug.trace("Adding option to ["+targetElement.id+"]["+this.selectedText+"]["+this.selectedValue+"]");
                if(this._Action == AjaxCtrlsExtenders.DragMode.Move)
                {
                    // TODO: modify to use remove method
                    //Sys.Debug.trace("Removing option from ["+sourceElement.id+"]["+this.selectedValue+"]");
                    this._RemoveListItem(sourceElement, this.selectedValue)
                    sourceElement.options[this.selectedIndex] = null;
                }
            }
            //sourceElement.selectedIndex = -1;
    },
    
    _resetDragging : function ()
    {
            this.selectedValue = "";
            this.selectedText = "";
            this.isDragging = false;
    },
    
    dumpThis : function (str){
//        var outstring = "";
//        outstring = "::" + str;
//        outstring += "\nthis.get_element().id)=[" + this.get_element().id + "]";
//        outstring += "\n$get(this._DropTargetID)=[" + $get(this._DropTargetID).id + "]";//$get(this._DropTargetID
//        outstring += "\nAction = [" + this._Action + "]";
//        outstring += "\nUnique = [" + this._Unique + "]";
//        outstring += "\nelement selectedIndex = [" + this.get_element().selectedIndex + "]";
//        outstring += "\nelement ListValue = [" + this.get_element().value + "]";
//        outstring += "\nelement ListText = [" + this.get_element().options[this.get_element().selectedIndex].innerHTML + "]";
//        alert(outstring);

        //Sys.Debug.trace("::" + str);
            //Sys.Debug.trace("this.get_element().id)=[" + this.get_element().id + "]");
            //Sys.Debug.trace("$get(this._DropTargetID)=[" + $get(this._DropTargetID).id + "]");
            //Sys.Debug.trace("Action = [" + this._Action + "]");
            //Sys.Debug.trace("Unique = [" + this._Unique + "]");
            //Sys.Debug.trace("element selectedIndex = [" + source.selectedIndex + "]");
            //Sys.Debug.trace("element ListValue = [" + source.value + "]");
            //Sys.Debug.trace("element ListText = [" + source.options[source.selectedIndex].innerHTML + "]");
    },
    
    _create_div_dynamic : function(e){
        var eventTargetElement = this._getEventTarget(e);
        var thisElement = this.get_element();
        var dropTargetElement = $get(this._DropTargetID);
        var mousePos = this._mouseCoords(e);
        
        // remove old ifr/div if they exist
        this._delete_div_dynamic();
        
        // calculate our ifr/div elements zindex to be greater than both source and destination listboxes
        var zindex = thisElement.style.zIndex+1;
        if(dropTargetElement.style.zIndex>= zindex)
        {
            zindex = dropTargetElement.style.zIndex+1;
        }
        
        var lineHeight = Math.ceil(thisElement.clientHeight/thisElement.size);
        
        // in MSIE, there are windowless and windowed objects.
        // Unfortunately listboxes are windowed and paint on top of all other objects.
        // See: http://support.microsoft.com/kb/927377 for IE7
        // See: http://support.microsoft.com/kb/177378 for INFO: How the Z-index Attribute Works for HTML Elements
        
                // create a div element
        var dv = document.createElement('div');
        dv.setAttribute('id',"dnd_dynamic_div");       //give id to it
        dv.className="top";                 // set the style classname  
        //set the inner styling of the div tag
        dv.style.cursor="hand"; 
        dv.style.position="absolute";       
        dv.style.zIndex = zindex+1;
        dv.style.left=mousePos.x+this.xoffset - this.offsetMouseDiv + "px";
        dv.style.top= (mousePos.y+this.yoffset - lineHeight) + this.offsetMouseDiv + "px";
//        dv.style.pixelLeft=mousePos.x;
//        dv.style.pixelTop=(mousePos.y - lineHeight) + "px";
        dv.style.pixelWidth=thisElement.clientWidth;
        dv.style.pixelHeight=lineHeight;
        dv.style.backgroundColor="red";
        // set the html content inside the div tag - Only displaying the display text and not the
        // select value itself.
        dv.innerHTML=thisElement.options[thisElement.selectedIndex].innerHTML;
        // store our selection information for use in copy/move function
        this.selectedIndex = thisElement.selectedIndex;
        this.selectedValue = thisElement.value;
        this.selectedText = thisElement.options[thisElement.selectedIndex].innerHTML;
        //add the div to the body 
        document.body.appendChild(dv);

        // create a frame element
        var ifr = document.createElement('iframe');
        ifr.setAttribute('id',"dnd_dynamic_ifr");       //give id to it
        ifr.className="top";                 // set the style classname  
        //set the inner styling of the div tag 
        ifr.style.position="absolute";      
        ifr.style.zIndex = zindex;
        ifr.height=lineHeight;
        ifr.width=thisElement.clientWidth;
        ifr.style.left=mousePos.x + this.xoffset - this.offsetMouseDiv + "px";
        ifr.style.top= (mousePos.y + this.yoffset - lineHeight) + this.offsetMouseDiv + "px";
        ifr.style.borderStyle = "none";
        //add the iframe to the body 
        document.body.appendChild(ifr);
    },
    
    _delete_div_dynamic : function(){
        var dv = document.getElementById("dnd_dynamic_div");
        if(dv)
        {
            document.body.removeChild(dv);
        }
        var ifr = document.getElementById('dnd_dynamic_ifr'); // remove iframe element
        if(ifr)
        {
            document.body.removeChild(ifr);
        }
    },
    
    // different browsers use different values for mouse positioning
    // determine what values are available in the event model and
    // return the correct x,y values.
    _mouseCoords : function(e) {
        if( !this.is_ie && (e.pageX || e.pageY))
        {
		    return {x:e.pageX, y:e.pageY};
        }
	    var cx = (e.clientX==null) ? 0 : e.clientX;
	    var cy = (e.clientY==null) ? 0 : e.clientY;
        var scrollLeft = (document.body.scrollLeft==null) ? 0 : document.body.scrollLeft;
	    var clientLeft = (document.body.clientLeft==null) ? 0 : document.body.clientLeft;
	    var scrollTop = (document.body.scrollTop==null) ? 0 : document.body.scrollTop;
	    var clientTop = (document.body.clientTop==null) ? 0 : document.body.clientTop;

	    return {
		    x:cx + scrollLeft - clientLeft,
		    y:cy + scrollTop - clientTop
		    };
    },
    /*
    
    //============================================================
// functions to find the X and Y coords of an element on which
// an event occurred - the event object is passed
//============================================================
function findPosX(e)
{
    var x = (e.offsetX) ? e.offsetX : e.layerX;
    var X = (e.pageX)   ? e.pageX   : e.clientX;
    var pos = X - x;
    return pos;
}

function findPosY(e)
{
    var y = (e.offsetY) ? e.offsetY : e.layerY;
    var Y = (e.pageY)   ? e.pageY   : e.clientY;
    var pos = Y - y;
    return pos;
}

    function findCoords(e) {
   if( !e ) { e = window.event; } if( !e || ( typeof( e.pageX ) != 'number' && typeof( e.clientX ) != 'number' ) ) { return [ 0, 0 ]; }
   if( typeof( e.pageX ) == 'number' ) { var posX = e.pageX; var posY = e.pageY; } else {
      var posX = e.clientX; var posY = e.clientY;
      if( !( ( window.navigator.userAgent.indexOf( 'Opera' ) + 1 ) || ( window.ScriptEngine && ScriptEngine().indexOf( 'InScript' ) + 1 ) || window.navigator.vendor == 'KDE' ) ) {
         if( document.documentElement && ( document.documentElement.scrollTop || document.documentElement.scrollLeft ) ) {
            posX += document.documentElement.scrollLeft; posY += document.documentElement.scrollTop;
         } else if( document.body && ( document.body.scrollTop || document.body.scrollLeft ) ) {
            posX += document.body.scrollLeft; posY += document.body.scrollTop;
         }
      }
      return [ posX, posY ];
   }
}
    */
    _DetectBrowserInfo: function() {
    // updated for IE7 - Howard Shank - 4/22/2008
    // Ultimate client-side JavaScript client sniff. Version 3.03
// (C) Netscape Communications 1999-2001.  Permission granted to reuse and distribute.
// Revised 17 May 99 to add is_nav5up and is_ie5up (see below).
// Revised 20 Dec 00 to add is_gecko and change is_nav5up to is_nav6up
//                      also added support for IE5.5 Opera4&5 HotJava3 AOLTV
// Revised 22 Feb 01 to correct Javascript Detection for IE 5.x, Opera 4, 
//                      correct Opera 5 detection
//                      add support for winME and win2k
//                      synch with browser-type-oo.js
// Revised 26 Mar 01 to correct Opera detection
// Revised 02 Oct 01 to add IE6 detection

// Everything you always wanted to know about your JavaScript client
// but were afraid to ask. Creates "is_" variables indicating:
// (1) browser vendor:
//     is_nav, is_ie, is_opera, is_hotjava, is_webtv, is_TVNavigator, is_AOLTV
// (2) browser version number:
//     is_major (integer indicating major version number: 2, 3, 4 ...)
//     is_minor (float   indicating full  version number: 2.02, 3.01, 4.04 ...)
// (3) browser vendor AND major version number
//     is_nav2, is_nav3, is_nav4, is_nav4up, is_nav6, is_nav6up, is_gecko, is_ie3,
//     is_ie4, is_ie4up, is_ie5, is_ie5up, is_ie5_5, is_ie5_5up, is_ie6, is_ie6up, is_hotjava3, is_hotjava3up,
//     is_opera2, is_opera3, is_opera4, is_opera5, is_opera5up
// (4) JavaScript version number:
//     is_js (float indicating full JavaScript version number: 1, 1.1, 1.2 ...)
// (5) OS platform and version:
//     is_win, is_win16, is_win32, is_win31, is_win95, is_winnt, is_win98, is_winme, is_win2k
//     is_os2
//     is_mac, is_mac68k, is_macppc
//     is_unix
//     is_sun, is_sun4, is_sun5, is_suni86
//     is_irix, is_irix5, is_irix6
//     is_hpux, is_hpux9, is_hpux10
//     is_aix, is_aix1, is_aix2, is_aix3, is_aix4
//     is_linux, is_sco, is_unixware, is_mpras, is_reliant
//     is_dec, is_sinix, is_freebsd, is_bsd
//     is_vms
//
// See http://www.it97.de/JavaScript/JS_tutorial/bstat/navobj.html and
// http://www.it97.de/JavaScript/JS_tutorial/bstat/Browseraol.html
// for detailed lists of userAgent strings.
//
// Note: you don't want your Nav4 or IE4 code to "turn off" or
// stop working when new versions of browsers are released, so
// in conditional code forks, use is_ie5up ("IE 5.0 or greater") 
// is_opera5up ("Opera 5.0 or greater") instead of is_ie5 or is_opera5
// to check version in code which you want to work on future
// versions.

    // convert all characters to lowercase to simplify testing
    var agt=navigator.userAgent.toLowerCase();

    // *** BROWSER VERSION ***
    // Note: On IE5, these return 4, so use is_ie5up to detect IE5.
    this.is_major = parseInt(navigator.appVersion);
    this.is_minor = parseFloat(navigator.appVersion);

    //alert("agt="+agt + "\nMajor="+this.is_major+" Minor="+this.is_minor);

    // Note: Opera and WebTV spoof Navigator.  We do strict client detection.
    // If you want to allow spoofing, take out the tests for opera and webtv.
    this.is_nav  = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
                && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
                && (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1));
    this.is_nav2 = (this.is_nav && (this.is_major == 2));
    this.is_nav3 = (this.is_nav && (this.is_major == 3));
    this.is_nav4 = (this.is_nav && (this.is_major == 4));
    this.is_nav4up = (this.is_nav && (this.is_major >= 4));
    this.is_navonly      = (this.is_nav && ((agt.indexOf(";nav") != -1) ||
                          (agt.indexOf("; nav") != -1)) );
    this.is_nav6 = (this.is_nav && (this.is_major == 5));
    this.is_nav6up = (this.is_nav && (this.is_major >= 5));
    this.is_gecko = (agt.indexOf('gecko') != -1);


    this.is_ie     = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
    this.is_ie3    = (this.is_ie && (this.is_major < 4));
    this.is_ie4    = (this.is_ie && (this.is_major == 4) && (agt.indexOf("msie 4")!=-1) );
    this.is_ie4up  = (this.is_ie && (this.is_major >= 4));
    this.is_ie5    = (this.is_ie && (this.is_major == 4) && (agt.indexOf("msie 5.0")!=-1) );
    this.is_ie5_5  = (this.is_ie && (this.is_major == 4) && (agt.indexOf("msie 5.5") !=-1));
    this.is_ie5up  = (this.is_ie && !this.is_ie3 && !this.is_ie4);
    this.is_ie5_5up =(this.is_ie && !this.is_ie3 && !this.is_ie4 && !this.is_ie5);
    this.is_ie6    = (this.is_ie && (this.is_major == 4) && (agt.indexOf("msie 6.")!=-1) );
    this.is_ie6up  = (this.is_ie && !this.is_ie3 && !this.is_ie4 && !this.is_ie5 && !this.is_ie5_5);
    this.is_ie7   = (this.is_ie && (this.is_major == 4) && (agt.indexOf("msie 7.")!=-1) );
    this.is_ie7up = (this.is_ie && !this.is_ie3 && !this.is_ie4 && !this.is_ie5 && !this.is_ie5_5 && !this.is_ie6);
    //alert("is_ie7="+this.is_ie7 + " & is_ie7up=" + this.is_ie7up);
    
    // KNOWN BUG: On AOL4, returns false if IE3 is embedded browser
    // or if this is the first browser window opened.  Thus the
    // variables this.is_aol, this.is_aol3, and this.is_aol4 aren't 100% reliable.
    this.is_aol   = (agt.indexOf("aol") != -1);
    this.is_aol3  = (this.is_aol && this.is_ie3);
    this.is_aol4  = (this.is_aol && this.is_ie4);
    this.is_aol5  = (agt.indexOf("aol 5") != -1);
    this.is_aol6  = (agt.indexOf("aol 6") != -1);

    this.is_opera = (agt.indexOf("opera") != -1);
    this.is_opera2 = (agt.indexOf("opera 2") != -1 || agt.indexOf("opera/2") != -1);
    this.is_opera3 = (agt.indexOf("opera 3") != -1 || agt.indexOf("opera/3") != -1);
    this.is_opera4 = (agt.indexOf("opera 4") != -1 || agt.indexOf("opera/4") != -1);
    this.is_opera5 = (agt.indexOf("opera 5") != -1 || agt.indexOf("opera/5") != -1);
    this.is_opera5up = (this.is_opera && !this.is_opera2 && !this.is_opera3 && !this.is_opera4);

    this.is_webtv = (agt.indexOf("webtv") != -1); 

    this.is_TVNavigator = ((agt.indexOf("navio") != -1) || (agt.indexOf("navio_aoltv") != -1)); 
    this.is_AOLTV = this.is_TVNavigator;

    this.is_hotjava = (agt.indexOf("hotjava") != -1);
    this.is_hotjava3 = (this.is_hotjava && (this.is_major == 3));
    this.is_hotjava3up = (this.is_hotjava && (this.is_major >= 3));

    // *** JAVASCRIPT VERSION CHECK ***
    if (this.is_nav2 || this.is_ie3) this.is_js = 1.0;
    else if (this.is_nav3) this.is_js = 1.1;
    else if (this.is_opera5up) this.is_js = 1.3;
    else if (this.is_opera) this.is_js = 1.1;
    else if ((this.is_nav4 && (this.is_minor <= 4.05)) || this.is_ie4) this.is_js = 1.2;
    else if ((this.is_nav4 && (this.is_minor > 4.05)) || this.is_ie5) this.is_js = 1.3;
    else if (this.is_hotjava3up) this.is_js = 1.4;
    else if (this.is_nav6 || this.is_gecko) this.is_js = 1.5;
    // NOTE: In the future, update this code when newer versions of JS
    // are released. For now, we try to provide some upward compatibility
    // so that future versions of Nav and IE will show they are at
    // *least* JS 1.x capable. Always check for JS version compatibility
    // with > or >=.
    else if (this.is_nav6up) this.is_js = 1.5;
    // NOTE: ie5up on mac is 1.4
    else if (this.is_ie5up) this.is_js = 1.3

    // HACK: no idea for other browsers; always check for JS version with > or >=
    else this.is_js = 0.0;

    // *** PLATFORM ***
    this.is_win   = ( (agt.indexOf("win")!=-1) || (agt.indexOf("16bit")!=-1) );
    // NOTE: On Opera 3.0, the userAgent string includes "Windows 95/NT4" on all
    //        Win32, so you can't distinguish between Win95 and WinNT.
    this.is_win95 = ((agt.indexOf("win95")!=-1) || (agt.indexOf("windows 95")!=-1));

    // is this a 16 bit compiled version?
    this.is_win16 = ((agt.indexOf("win16")!=-1) || 
               (agt.indexOf("16bit")!=-1) || (agt.indexOf("windows 3.1")!=-1) || 
               (agt.indexOf("windows 16-bit")!=-1) );  

    this.is_win31 = ((agt.indexOf("windows 3.1")!=-1) || (agt.indexOf("win16")!=-1) ||
                    (agt.indexOf("windows 16-bit")!=-1));

    this.is_winme = ((agt.indexOf("win 9x 4.90")!=-1));
    this.is_win2k = ((agt.indexOf("windows nt 5.0")!=-1));
    this.is_winXP = ((agt.indexOf("windows nt 5.1")!=-1));
    this.is_win2k3 = ((agt.indexOf("windows nt 5.2")!=-1));
    this.is_winVista = ((agt.indexOf("windows nt 6.0")!=-1));
    //this.is_win2k8 = ((agt.indexOf("windows nt 6.1")!=-1));

    // NOTE: Reliable detection of Win98 may not be possible. It appears that:
    //       - On Nav 4.x and before you'll get plain "Windows" in userAgent.
    //       - On Mercury client, the 32-bit version will return "Win98", but
    //         the 16-bit version running on Win98 will still return "Win95".
    this.is_win98 = ((agt.indexOf("win98")!=-1) || (agt.indexOf("windows 98")!=-1));
    this.is_winnt = ((agt.indexOf("winnt")!=-1) || (agt.indexOf("windows nt")!=-1));
    this.is_win32 = (this.is_win95 || this.is_winnt || this.is_win98 || 
                    ((this.is_major >= 4) && (navigator.platform == "Win32")) ||
                    (agt.indexOf("win32")!=-1) || (agt.indexOf("32bit")!=-1));

    this.is_os2   = ((agt.indexOf("os/2")!=-1) || 
                    (navigator.appVersion.indexOf("OS/2")!=-1) ||   
                    (agt.indexOf("ibm-webexplorer")!=-1));

    this.is_mac    = (agt.indexOf("mac")!=-1);
    this.is_safari    = (agt.indexOf("apple")!=-1);
    // hack ie5 js version for mac
    if (this.is_mac && this.is_ie5up) this.is_js = 1.4;
    this.is_mac68k = (this.is_mac && ((agt.indexOf("68k")!=-1) || 
                               (agt.indexOf("68000")!=-1)));
    this.is_macppc = (this.is_mac && ((agt.indexOf("ppc")!=-1) || 
                                (agt.indexOf("powerpc")!=-1)));

    this.is_sun   = (agt.indexOf("sunos")!=-1);
    this.is_sun4  = (agt.indexOf("sunos 4")!=-1);
    this.is_sun5  = (agt.indexOf("sunos 5")!=-1);
    this.is_suni86= (this.is_sun && (agt.indexOf("i86")!=-1));
    this.is_irix  = (agt.indexOf("irix") !=-1);    // SGI
    this.is_irix5 = (agt.indexOf("irix 5") !=-1);
    this.is_irix6 = ((agt.indexOf("irix 6") !=-1) || (agt.indexOf("irix6") !=-1));
    this.is_hpux  = (agt.indexOf("hp-ux")!=-1);
    this.is_hpux9 = (this.is_hpux && (agt.indexOf("09.")!=-1));
    this.is_hpux10= (this.is_hpux && (agt.indexOf("10.")!=-1));
    this.is_aix   = (agt.indexOf("aix") !=-1);      // IBM
    this.is_aix1  = (agt.indexOf("aix 1") !=-1);    
    this.is_aix2  = (agt.indexOf("aix 2") !=-1);    
    this.is_aix3  = (agt.indexOf("aix 3") !=-1);    
    this.is_aix4  = (agt.indexOf("aix 4") !=-1);    
    this.is_linux = (agt.indexOf("inux")!=-1);
    this.is_sco   = (agt.indexOf("sco")!=-1) || (agt.indexOf("unix_sv")!=-1);
    this.is_unixware = (agt.indexOf("unix_system_v")!=-1); 
    this.is_mpras    = (agt.indexOf("ncr")!=-1); 
    this.is_reliant  = (agt.indexOf("reliantunix")!=-1);
    this.is_dec   = ((agt.indexOf("dec")!=-1) || (agt.indexOf("osf1")!=-1) || 
           (agt.indexOf("dec_alpha")!=-1) || (agt.indexOf("alphaserver")!=-1) || 
           (agt.indexOf("ultrix")!=-1) || (agt.indexOf("alphastation")!=-1)); 
    this.is_sinix = (agt.indexOf("sinix")!=-1);
    this.is_freebsd = (agt.indexOf("freebsd")!=-1);
    this.is_bsd = (agt.indexOf("bsd")!=-1);
    this.is_unix  = ((agt.indexOf("x11")!=-1) || this.is_sun || this.is_irix || this.is_hpux || 
                 this.is_sco ||this.is_unixware || this.is_mpras || this.is_reliant || 
                 this.is_dec || this.is_sinix || this.is_aix || this.is_linux || this.is_bsd || this.is_freebsd);

    this.is_vms   = ((agt.indexOf("vax")!=-1) || (agt.indexOf("openvms")!=-1));
    }
}

AjaxCtrlsExtenders.DragDropListboxBehavior.registerClass('AjaxCtrlsExtenders.DragDropListboxBehavior', AjaxControlToolkit.BehaviorBase);
